package string;

/**
 * 字符串String
 * 内部使用一个char数组保存所有字符，每个字符为2字节，存的是该字符unicode编码
 * 字符串是不变对象，一旦创建内容不可改变，若改变会创建新对象
 */


public class StringDemo {
    public static void main(String[] args) {
  /*
  字符串常量池
  java在堆内存中开辟了一段空间用于缓冲所有使用字面量形式创建的字符串对象，
  并在后期再次使用该字面量创建字符串时重用对象，避免内存中堆积大量内容一样的
  字符串对象来减小内存开销。
 */
        String s1="123abc";//字面量
        String s2="123abc";//与s1字面量相同，重用对象
        //地址相同，说明s2重用了s1对象
        System.out.println(s1==s2);//ture
        String s3="123abc";
        System.out.println(s1==s3);//ture
        String s4=new String("123abc");//new会产生新对象
        System.out.println("s4:"+s4);
        System.out.println(s1==s4);//false
        /*
        通常我们判断字符串都是比较内容，因此应当使用字符串的equal方法
         */
        System.out.println(s1.equals(s4));//true
/*
      由于字符串是不变对象，改变内容会产生新对象
 */
        s1=s1+"!";//生成一个新字符串对象123abc！
        System.out.println("s1:"+s1);//123abc!
        System.out.println("s2:"+s2);//123abc
        System.out.println(s1==s2);//false  s1,s2已经不再指向同一个对象了
        /*
        这里触发了一个编译器的特性
        编译器在编译期间若遇到几个计算表达式，发现在编译器可以确定结果时就会进行计算
        并将结果编译到class文件中，这样一来JVM每次执行字节码文件就无需在计算了。
        下面代码会被编译期改为：
        String s5="123abc";
        也因此s5会重用常量池中的对象，所以地址与s2相同
         */
        String s5="123"+"abc";
        System.out.println("s5:"+s5);//123abc
        System.out.println(s2==s5);//true
        String s="123";
        String s6=s+"abc";
        System.out.println("s6:"+s6);//s6:123abc
        System.out.println(s2==s6);//false
        String s7=1+2+3+"abc";//6abc
        System.out.println(s2==s7);//false
        String s8=1+'2'+3+"abc";//'2'是char类型，'2'为50
        System.out.println("s8:"+s8);//54abc
        System.out.println(s2==s8);//false
        String s9=1+"2"+3+"abc";
        System.out.println(s2==s9);//true
    }
}
